#pragma once

#include <iostream>
#include <functional>
#include "Connection.hpp"

using func_t = std::function<std::string(std::string&)>;

// 只负责IO
class IOService : public Connection
{
    const static int size = 1024;
public:
    IOService(int sockfd, InetAddr peer)
    {
        SetSockfd(sockfd);
        SetNonBlock(sockfd); // 设置为非阻塞
        SetEvents(EPOLLIN | EPOLLET);
        SetPeer(peer);
    }
    ~IOService()
    {}

    void RegisterOnMessage(func_t on_message)
    {
        _on_message = on_message;
    }

    virtual void Recver() override
    {
        while (true)
        {
            char buffer[size];
            // 无法保证我们读取上来的报文是一个完整的报文！！！
            ssize_t n = ::recv(GetSockfd(), buffer, sizeof(buffer)-1, 0);
            if (n > 0)
            {
                buffer[n] = 0;
                AppendInBuffer(buffer);
            }
            else if (n == 0)
            {
                // 客户端把连接关闭了
                Excepter();
                break;
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    Excepter();
                    return;
                }
            }
        }
        // 到这里说明读取完成，我们无法保证读取的报文是一个完整的报文，所以需要协议处理
        std::string result;
        if (_on_message)
        {
            result = _on_message(GetInBuffer());
        }
        // 如果没有一个完整报文，添加空串不影响
        AppendOutBuffer(result);
        if (!GetOutBuffer().empty())
        {
            // 方案1:直接Sender写入
            // 方案2:使能Write
            Sender();
            // GetOwner()->EnableReadWrite(GetSockfd(), true, true);
        }
    }

    virtual void Sender() override
    {
        while (true)
        {
            ssize_t n = send(GetSockfd(), GetOutBuffer().c_str(), GetOutBuffer().size(), 0);
            if (n > 0)
            {
                EraseOutBuffer(n);
            }
            else if (n == 0) 
            {
                // outbuffer没数据了.
                break;
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    // 写缓冲区满了，下次再写
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    Excepter();
                    return;
                }
            }
        }

        // 1. outbuffer数据写完了
        // 2. 发送缓冲区被写满了，outbuffer不为空，写条件不满足，使能sockfd在epoll中的事件
        // 如果outbuffer还有数据，就将读事件添加到epoll模型中
        if (!GetOutBuffer().empty())
        {
            GetOwner()->EnableReadWrite(GetSockfd(), true, true);
        }
        else
        {
            GetOwner()->EnableReadWrite(GetSockfd(), true, false);
        }
    }

    // IO读取的时候，所有的异常处理，全部都会转化成为这个一个函数的调用
    // 出现异常，我们怎么做？？？
    // 打印日志，差错处理，关闭连接，Reactor异常connection, 从内核中，移除对fd的关心
    virtual void Excepter() override
    {
        LOG(LogLevel::WARNING) << "客户端连接可能结束，进行异常处理: " << GetSockfd();
        GetOwner()->DeleteConnection(GetSockfd());
    } 
private:
    func_t _on_message;
};